%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: 
%% Progress to usefulness: 
%%
%%%%%%%%%%%%%%%%%%%%%%%

-module(chord_distributed).
-include("db.hrl").

-export([lookup_call/3, lookup_cast/3,
         find_successor/2, find_successor_call/3, find_successor_cast/3,
         find_predecessor/2, find_predecessor_call/3, find_predecessor_cast/3]).

-import(chord_lib, [dbg_str/2, dbg_format/3, dbg_header/2]).
-import(chord_lib, [dbg_msg/2, dbg_msg_loc/2]).
-import(chord_lib, [get_node/1, get_pid/1, get_position/1]).
-import(chord_lib, [get_finger/2, set_finger/3, finger_start/2, get_M/0, modspace/1]).

lookup_call(Key, From, State) ->
    dbg_format("Looking up key ~p on behalf of caller ~p~n", [Key, From], State),
    Hash = hash:hash(Key),
    lookup_cast(Hash, From, State).

lookup_cast(Hash, From, State) ->
    Self = State#chord.identity,
    SelfPos = Self#node.position,
    Succ = get_finger(1, State),
    SuccPos = Succ#node.position,
    case intmath:interval_check_exc_inc(SelfPos, Hash, SuccPos) of
      true ->
        dbg_str("lookup_cast: Success~n", State),
        %% And reply to caller, by using gen_server:reply,
        %% the caller thinks he made a synchronous call
        gen_server:reply(From, Succ#node.node);
      false ->
        Next = chord_lib:closest_preceding_finger(Hash, State),
        case Next == Self of
          true ->
            dbg_str("lookup_cast: Fail. Returning identity. ~n", State),
            gen_server:reply(From, Self#node.node);
          false ->
            dbg_format("lookup_cast: Fail. Forwarding to node ~p~n", [Next#node.node], State),
            chord_lib:rem_query_cast(Next, {lookup_cast, Hash, From}, State)
        end
    end.

%% With the help of the other nodes, find the immediate 
%% successor node to the identifier Id. 
find_successor(Id, State) ->
  dbg_format("find_successor: Finding suc for pos ~B~n", [Id], State),
  Self = State#chord.identity,
  case Id == Self#node.position of
    true ->
      dbg_str("find_successor: Asking for the identity node~n", State),
      chord_lib:wrap_get_successor(State, Self);
    false ->
      gen_server:call(?NETWORK, {find_successor, Id})
  end.

find_successor_call(Id, From, State) ->
    find_successor_cast(Id, From, State).

find_successor_cast(Hash, From, State) ->
    Self = State#chord.identity,
    SelfPos = Self#node.position,
    Succ = get_finger(1, State),
    SuccPos = Succ#node.position,
    case intmath:interval_check_exc_inc(SelfPos, Hash, SuccPos) of
      true ->
        dbg_str("find_successor_cast: Success~n", State),
        %% And reply to caller, by using gen_server:reply,
        %% the caller thinks he made a synchronous call
        gen_server:reply(From, Succ);
      false ->
        Next = chord_lib:closest_preceding_finger(Hash, State),
        case Next == Self of
          true ->
            dbg_str("find_successor_cast: Fail. Returning identity. ~n", State),
            gen_server:reply(From, Self);
          false ->
            dbg_format("find_successor_cast: Fail. Forwarding to node ~p~n", [Next#node.node], State),
            chord_lib:rem_query_cast(Next, {find_successor_cast, Hash, From}, State)
        end
    end.

%% With the help of the other nodes, find the immediate 
%% predecessor node to the identifier Id. 
find_predecessor(Id, State) ->
  dbg_format("find_predecessor: Finding pred for pos ~B~n", [Id], State),
  N2 = State#chord.identity,
  case Id == N2#node.position of
    true ->
      dbg_str("find_predecessor: Asking for the identity node~n", State),
      chord_lib:wrap_get_predecessor(State, N2);
    false ->
      gen_server:call(?NETWORK, {find_predecessor, Id})
  end.

find_predecessor_call(Id, From, State) ->
     find_predecessor_cast(Id, From, State).

find_predecessor_cast(Hash, From, State) ->
    Self = State#chord.identity,
    SelfPos = Self#node.position,
    Succ = get_finger(1, State),
    SuccPos = Succ#node.position,
    case intmath:interval_check_exc_inc(SelfPos, Hash, SuccPos) of
      true ->
        dbg_str("find_predecessor_cast: Success~n", State),
        %% And reply to caller, by using gen_server:reply,
        %% the caller thinks he made a synchronous call
        gen_server:reply(From, Self);
      false ->
        Next = chord_lib:closest_preceding_finger(Hash, State),
        case Next == Self of
          true ->
            dbg_str("find_predecessor_cast: Fail. Returning identity. ~n", State),
            gen_server:reply(From, Self);
          false ->
            dbg_format("find_predecessor_cast: Fail. Forwarding to node ~p~n", [Next#node.node], State),
            chord_lib:rem_query_cast(Next, {find_predecessor_cast, Hash, From}, State)
        end
    end.
